/*!
 * \file CplexDesigualdades.cpp
 *
 * \date Aug 14, 2014
 * \author correa
 */
#include "CplexDesigualdades.h"

using namespace std;

RangeDesigualdad::RangeDesigualdad(IloNumVarArray& x, IloRange& range) : Desigualdad(x.getSize(), x.getSize()), _x(x), _range(range)
{
}

RangeDesigualdad::RangeDesigualdad(IloNumVarArray& x, IloRange& range, int nv, int nx) : Desigualdad(nv, nx), _x(x), _range(range)
{
}

RangeDesigualdad::RangeDesigualdad(const RangeDesigualdad& otra) : Desigualdad(otra), _x(otra._x), _range(otra._range)
{
}

RangeDesigualdad::RangeDesigualdad(const RangeDesigualdad&& otra) : Desigualdad(otra), _x(otra._x), _range(otra._range)
{
}

RangeDesigualdad::~RangeDesigualdad()
{
}

RangeDesigualdad& RangeDesigualdad::operator=(RangeDesigualdad const& otra)
{
	Desigualdad::operator=(otra);
	_x = otra._x;
	_range = otra._range;

	return *this;
}

RangeDesigualdad& RangeDesigualdad::operator=(RangeDesigualdad&& otra)
{
	Desigualdad::operator=(otra);
	_x = otra._x;
	_range = otra._range;

	return *this;
}

void RangeDesigualdad::setCoeficiente(int i, int coef)
{
	_range.setLinearCoef(_x[i], coef);
	Desigualdad::setCoeficiente(i, coef);
}

int RangeDesigualdad::getRHS() const
{
	return _range.getUB();
}

void RangeDesigualdad::setRHS(int valor)
{
	_range.setUB(valor);
}

void RangeDesigualdad::print()
{
	VertexSetIterator iti = getSoporte().begin();
	for (; iti != getSoporte().end(); ++iti)
		cout << " + " << getCoeficiente(*iti) << _x[*iti].getName();
	cout << " <= " << getRHS() << "\n";
}

CplexDesigualdad::CplexDesigualdad(IloNumVarArray& x) : IloRange(x.getEnv(), 0, x.getSize()), RangeDesigualdad(x, *this)
{
}

CplexDesigualdad::CplexDesigualdad(IloNumVarArray& x, int nv, int nx) : IloRange(x.getEnv(), 0, x.getSize()), RangeDesigualdad(x, *this, nv, nx)
{
}

CplexDesigualdad::CplexDesigualdad(const CplexDesigualdad& otra) : IloRange(otra._x.getEnv(), 0, otra, otra.getRHS()), RangeDesigualdad(otra)
{
}

CplexDesigualdad::~CplexDesigualdad()
{
}

RepRangeDesigualdad::RepRangeDesigualdad(int rep, IloNumVarArray& x, IloRange& range, MatrixOfRepresentaciones& mapa, ArrayOfRepresentaciones& array, bool dummy) : RangeDesigualdad(x, range, 0, 0), _mapa(mapa), _array(array), _rep(rep)
{
}

RepRangeDesigualdad::RepRangeDesigualdad(int rep, IloNumVarArray& x, IloRange& range, MatrixOfRepresentaciones& mapa, ArrayOfRepresentaciones& array) : RangeDesigualdad(x, range, mapa.capacity(), mapa[rep].size()), _mapa(mapa), _array(array), _rep(rep)
{
}

RepRangeDesigualdad::RepRangeDesigualdad(const RepRangeDesigualdad& otra) : RangeDesigualdad(otra), _mapa(otra._mapa), _array(otra._array), _rep(otra._rep)
{
}

RepRangeDesigualdad::RepRangeDesigualdad(const RepRangeDesigualdad&& otra) : RangeDesigualdad(otra), _mapa(otra._mapa), _array(otra._array), _rep(otra._rep)
{
}

RepRangeDesigualdad& RepRangeDesigualdad::operator=(RepRangeDesigualdad const& otra)
{
	RangeDesigualdad::operator=(otra);
	_mapa = otra._mapa;
	_array = otra._array;
	_rep = otra._rep;

	return *this;
}

RepRangeDesigualdad& RepRangeDesigualdad::operator=(RepRangeDesigualdad&& otra)
{
	RangeDesigualdad::operator=(otra);
	_mapa = otra._mapa;
	_array = otra._array;
	_rep = otra._rep;

	return *this;
}

int RepRangeDesigualdad::getCoeficiente(int i) {
//	cout << "mapa[" << _rep << "][" << i << "]=" << _mapa[_rep][i] << endl;
	i = _mapa[_rep][i];
	if (i < 0)
		return 0;
	return Desigualdad::getCoeficiente(i);
}

void RepRangeDesigualdad::setCoeficiente(int i, int coef) {
	_range.setLinearCoef(_x[_array[_rep][i]], coef);
	_coef->setValue(_mapa[_rep][i], coef);
	_soporte->add(i);
}

const IntValueArray& RepRangeDesigualdad::getCoeficientes() {
	class ColorIntValueArray : public IntValueArray
	{
		RepRangeDesigualdad * _d;
	public:
		ColorIntValueArray(RepRangeDesigualdad * d, const IntValueArray& a) : _d(d), IntValueArray(a) {};
		virtual ~ColorIntValueArray() {};
		const int operator [](int i) const { i = _d->_mapa[_d->_rep][i]; if (i < 0) return 0; return IntValueArray::operator [](i); };
		int operator [](int i) { i = _d->_mapa[_d->_rep][i]; if (i < 0) return 0; return IntValueArray::operator [](i); };
		void setValue(const int i, const int valor) { int j = _d->_mapa[_d->_rep][i]; if (j >= 0) IntValueArray::setValue(j, valor); };
		int capacity() const { return _d->_mapa.capacity(); };
	};
	return *(new ColorIntValueArray(this, Desigualdad::getCoeficientes()));
}

void RepRangeDesigualdad::print()
{
	VertexSetIterator iti = getSoporte().begin();
	for (; iti != getSoporte().end(); ++iti)
		cout << " + " << getCoeficiente(*iti) << _x[_array[_rep][*iti]].getName();
}

CplexSubRepDesigualdad::CplexSubRepDesigualdad(int rep, IloNumVarArray& x, MatrixOfRepresentaciones& mapa, ArrayOfRepresentaciones& array) : IloRange(x.getEnv(), 0, x.getSize()), RepRangeDesigualdad(rep, x, *this, mapa, array)
{
}

CplexSubRepDesigualdad::CplexSubRepDesigualdad(const CplexSubRepDesigualdad& otra) : IloRange(otra._x.getEnv(), 0, otra, otra.getRHS()), RepRangeDesigualdad(otra)
{
}

CplexSubRepDesigualdad::~CplexSubRepDesigualdad() {};

void CplexSubRepDesigualdad::setRHS(int valor)
{
	setCoeficiente(_rep, valor);
	RangeDesigualdad::setRHS(valor);
}

int CplexSubRepDesigualdad::getRHS() const
{
	return RangeDesigualdad::getRHS();
}

void CplexSubRepDesigualdad::print()
{
	RepRangeDesigualdad::print();
	cout << " <= " << getRHS() << endl;
}

CplexRepDesigualdad::CplexRepDesigualdad(IloNumVarArray& x, MatrixOfRepresentaciones& mapa, ArrayOfRepresentaciones& array) : IloRange(x.getEnv(), 0, x.getSize()), DesigualdadArray<RepRangeDesigualdad>(), _x(x), _mapa(mapa), _array(array)
{
	resize(_mapa.capacity(), RepRangeDesigualdad(-1, x, *this, mapa, array, true));
}

RepRangeDesigualdad& CplexRepDesigualdad::operator[](int i)
{
	RepRangeDesigualdad& ret = DesigualdadArray<RepRangeDesigualdad>::operator [](i);
	if (ret._rep < 0) {
		ret.resize(_mapa.capacity(), _mapa[i].size());
		ret._rep = i;
	}
	return ret;
}

void CplexRepDesigualdad::setRHS(int valor)
{
	setUB(valor);
}

int CplexRepDesigualdad::getRHS() const
{
	return getUB();
}

void CplexRepDesigualdad::print()
{
	for (int i = 0; i < size(); i++) {
		RepRangeDesigualdad& item = DesigualdadArray<RepRangeDesigualdad>::operator [](i);
		if (item._rep >= 0)
			item.print();
	}
	cout << " <= " << getRHS() << endl;
}

template <>
void DesigualdadArray<RepRangeDesigualdad>::print()
{
	for (iterator it = begin(); it != vector<RepRangeDesigualdad>::end(); ++it)
		(*it).print();
}
